﻿using XNET.Extension;

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;

namespace XNET.SQL
{
    /// <summary>
    /// 数据库访问类，带command命令
    /// </summary>
    public class XCommand : IDatabase
    {
        /// <summary>
        /// 表示要对数据源执行的 SQL 语句或存储过程。 为表示命令的、数据库特有的类提供一个基类
        /// </summary>
        public readonly DbCommand Command;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cmd"></param>
        public XCommand(DbCommand cmd)
        {
            Command = cmd;
        }
        /// <summary>
        /// 设置参数
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        private void PrepareCommand(string sql, object parameters)
        {
            Command.CommandType = CommandType.Text;
            Command.CommandText = sql;
            Command.SetParameters(parameters);
        }
        /// <summary>
        /// 执行SQL语句返回影响行数
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters"> 参数</param>
        /// <returns></returns>
        public int ExecuteNonQuery(string sql, object parameters)
        {
            PrepareCommand(sql, parameters);

            return Command.ExecuteNonQuery();
        }
        /// <summary>
        /// 执行SQL语句查询返回集合
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <param name="action">返回事件</param>
        /// <returns></returns>
        public IEnumerable<T> ExecuteDataReader<T>(string sql, object parameters, Func<DbDataReader, T> action)
        {
            PrepareCommand(sql, parameters);

            using (var dr = Command.ExecuteReader())
            {
                while (dr.Read())
                    yield return action.Invoke(dr);
            }
        }
        /// <summary>
        /// 执行SQL语句查询返回集合
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <param name="action">返回集合事件</param>
        public void ExecuteDataReader(string sql, object parameters, Action<DbDataReader> action)
        {
            PrepareCommand(sql, parameters);

            using (var dr = Command.ExecuteReader())
            {
                while (dr.Read())
                    action.Invoke(dr);
            }
        }
        /// <summary>
        /// 执行事务
        /// </summary>
        /// <param name="action">在事件中所有查询，修改，插入操作都在一个事务</param>
        public void ExecuteTransaction(Action<IDatabase> action)
        {
            if (action != null)
                action.Invoke(this);
        }
        /// <summary>
        /// 返回单个值
        /// </summary>
        /// <typeparam name="T">返回类型</typeparam>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public T ExecuteScalar<T>(string sql, object parameters)
        {
            PrepareCommand(sql, parameters);

            return (T)Command.ExecuteScalar();
        }
        /// <summary>
        /// 批量复制
        /// </summary>
        /// <param name="table">数据表</param>
        /// <param name="batchSize">每次复制条数</param>
        public void BulkCopy(DataTable table, int batchSize)
        {
            using (var bulkcopy = new SqlBulkCopy((SqlConnection)Command.Connection))
            {
                if (table != null && table.Rows.Count > 0)
                {
                    bulkcopy.DestinationTableName = table.TableName;
                    bulkcopy.BatchSize = 100;
                    bulkcopy.WriteToServer(table);
                }
            }
        }
        /// <summary>
        /// 判断是否存在行
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">参数</param>
        /// <returns></returns>
        public bool HasRow(string sql, object parameters)
        {
            Command.CommandType = CommandType.Text;
            Command.CommandText = sql;
            Command.SetParameters(parameters);

            using (var dr = Command.ExecuteReader())
            {
                return dr.HasRows;
            }
        }
    }
}
